#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include "../src/qfunc.c"

typedef struct _QfuncTestDatum QfuncTestDatum;
struct _QfuncTestDatum 
{
  struct
    {
      double kappa;
      double logalpha[3];
      double tau[4*(5-1)];
      double gamma[(5-1)];
      double pz[3*5];
      double priorz[5];
      Rating ratings[8];
      double priorlogalphavar;
      double priortauvar;
      double priorgamma1mean;
      double priorgamma1var;
      double priorgamma2mean;
      double priorgamma2var;
      double priorgamma3mean;
      double priorgamma3var;
      double priorgamma4mean;
      double priorgamma4var;
      double priorkappamean;
      double priorkappavar;
    }                           input;

  double                        output;
};

static void
test_qfunc (void)
{
  QfuncTestDatum data[] = 
    {{{0.777273, {0.234941, 0.14725, 0.714091}, {0.231416, 0.738539,  0.164945, 0.27892, 0.7121, 0.465945, 0.480999, 0.50437, 0.573495,  0.063727, 0.679937, 0.299955, 0.686796, 0.654826, 0.86413,  0.144492}, {0.121597, 0.787895, 0.134168, 0.82248}, {0.344323,  0.552954, 0.986918, 0.108388, 0.112907, 0.814415, 0.821973,  0.829468, 0.400807, 0.34847, 0.340974, 0.325099, 0.827312,  0.284743, 0.661037}, {0.0251436, 0.140516, 0.629917, 0.796907,  0.880652}, {{1, 2, 2}, {3, 1, 0}, {0, 1, 3}, {1, 1, 3}, {2, 0,  2}, {1, 2, 0}, {1, 2, 4}, {1, 1, 0}}, 0.0189195, 0.842022,  0.662739, 0.058172, 0.674596, 0.289068, 0.675821, 0.949784,  0.561689, 0.474653, 0.853848,  0.120315}, -1144.15}, {{0.160882, {0.126183, 0.512874,  0.795216}, {0.33357, 0.84144, 0.851837, 0.770073, 0.193054,  0.211522, 0.0549297, 0.889421, 0.174134, 0.3695, 0.392191,  0.831249, 0.499538, 0.0804317, 0.716369, 0.881466}, {0.937849,  0.605779, 0.862521, 0.76115}, {0.776967, 0.479596, 0.349647,  0.965934, 0.443397, 0.638156, 0.49781, 0.195861, 0.250343,  0.426634, 0.44288, 0.30644, 0.0762089, 0.0571336,  0.0506894}, {0.475191, 0.576671, 0.976702, 0.33432,  0.593725}, {{2, 0, 2}, {3, 0, 2}, {0, 2, 0}, {1, 0, 0}, {0, 2,  0}, {0, 2, 1}, {3, 2, 4}, {2, 2, 0}}, 0.638822, 0.370923,  0.471799, 0.832575, 0.861855, 0.891328, 0.122153, 0.866641,  0.418458, 0.253172, 0.624343,  0.67078}, -90.2553}, {{0.168115, {0.826538, 0.181463,  0.36434}, {0.0919058, 0.769404, 0.130774, 0.889149, 0.515235,  0.792703, 0.796453, 0.295424, 0.876413, 0.421779, 0.324654,  0.462849, 0.0145584, 0.530451, 0.202502, 0.596208}, {0.596101,  0.27728, 0.578159, 0.925428}, {0.427986, 0.450742, 0.396696,  0.561087, 0.33608, 0.681337, 0.265922, 0.671938, 0.820845,  0.888635, 0.469469, 0.376514, 0.944432, 0.466855,  0.144814}, {0.913665, 0.929873, 0.936404, 0.942313,  0.317457}, {{3, 0, 3}, {3, 0, 2}, {2, 2, 0}, {2, 0, 3}, {2, 1,  3}, {1, 2, 4}, {0, 1, 3}, {2, 1, 2}}, 0.333773, 0.659125,  0.364154, 0.392029, 0.905787, 0.208383, 0.967458, 0.830942,  0.569707, 0.527046, 0.701536,  0.159004}, -117.552}, {{0.748862, {0.638411, 0.232068,  0.78249}, {0.80443, 0.171556, 0.0872532, 0.868825, 0.874557,  0.235152, 0.14494, 0.551368, 0.540784, 0.576027, 0.780786,  0.159339, 0.634997, 0.367644, 0.813328, 0.328397}, {0.0652898,  0.840598, 0.111791, 0.169393}, {0.316428, 0.202187, 0.879724,  0.386903, 0.511998, 0.030631, 0.79247, 0.518078, 0.637442,  0.795479, 0.64753, 0.96671, 0.0966578, 0.219452,  0.866744}, {0.807371, 0.461661, 0.851808, 0.0534164,  0.478975}, {{3, 1, 0}, {0, 2, 2}, {0, 1, 3}, {2, 0, 1}, {3, 2,  3}, {2, 2, 2}, {0, 2, 1}, {3, 0, 1}}, 0.396371, 0.0112097,  0.941625, 0.309582, 0.0799432, 0.809023, 0.0619014, 0.922679,  0.567945, 0.778392, 0.269431,  0.404602}, -17880.9}, {{0.930504, {0.982913, 0.621901,  0.437892}, {0.833846, 0.76346, 0.755157, 0.63052, 0.372185,  0.911653, 0.70174, 0.151546, 0.975813, 0.900443, 0.760115,  0.841963, 0.89587, 0.0914199, 0.698214, 0.919284}, {0.327925,  0.313028, 0.428783, 0.514682}, {0.397421, 0.330115, 0.806882,  0.0767906, 0.563576, 0.566655, 0.0517253, 0.44627, 0.191391,  0.655003, 0.349985, 0.294725, 0.215577, 0.75456,  0.589869}, {0.452761, 0.319707, 0.66314, 0.891655,  0.533477}, {{1, 0, 4}, {0, 0, 3}, {0, 2, 3}, {3, 1, 0}, {3, 2,  2}, {2, 0, 4}, {3, 1, 1}, {0, 0, 2}}, 0.991782, 0.350112,  0.462872, 0.0187948, 0.594361, 0.0199963, 0.65599, 0.942004,  0.0307852, 0.453341, 0.604265,  0.495734}, -239.394}, {{0.839394, {0.798339, 0.25428,  0.201009}, {0.623817, 0.043779, 0.664411, 0.748248, 0.30411,  0.380639, 0.772755, 0.214771, 0.312327, 0.0305275, 0.309883,  0.195976, 0.717967, 0.0105312, 0.653893, 0.253972}, {0.687182,  0.55719, 0.0496275, 0.758238}, {0.847787, 0.758851, 0.795347,  0.557228, 0.22397, 0.715072, 0.130936, 0.80898, 0.919861,  0.334433, 0.358181, 0.59421, 0.607533, 0.303905,  0.0482981}, {0.398234, 0.889567, 0.293374, 0.394405,  0.144262}, {{2, 1, 2}, {3, 0, 3}, {1, 0, 4}, {3, 1, 0}, {2, 2,  2}, {1, 2, 4}, {0, 2, 1}, {3, 0, 2}}, 0.202385, 0.736184,  0.344778, 0.386024, 0.354598, 0.977333, 0.549431, 0.828796,  0.130627, 0.262261, 0.418494,  0.0198154}, -349.387}, {{0.210767, {0.927828, 0.0603132,  0.425606}, {0.603233, 0.623923, 0.0120151, 0.0273718, 0.713667,  0.330549, 0.61761, 0.88311, 0.511282, 0.594364, 0.272832,  0.497085, 0.156684, 0.617031, 0.723401, 0.668289}, {0.0260568,  0.35477, 0.304907, 0.648474}, {0.81529, 0.426942, 0.244594,  0.222868, 0.212057, 0.803019, 0.232578, 0.195496, 0.49839,  0.47247, 0.614969, 0.312387, 0.987108, 0.878105,  0.342137}, {0.815301, 0.830424, 0.261074, 0.618736,  0.147012}, {{0, 0, 4}, {3, 1, 0}, {2, 0, 0}, {2, 0, 1}, {0, 2,  1}, {0, 2, 0}, {1, 2, 0}, {3, 1, 2}}, 0.804367, 0.906304,  0.313829, 0.498538, 0.989077, 0.479362, 0.069236, 0.27567, 0.77702,  0.676344, 0.836658,  0.0801739}, -206.039}, {{0.27863, {0.203874, 0.221689,  0.767787}, {0.291523, 0.325769, 0.879552, 0.952486, 0.461099,  0.0646947, 0.260815, 0.805474, 0.656732, 0.158391, 0.946986,  0.306935, 0.667656, 0.679028, 0.87775, 0.0312651}, {0.890636,  0.00268445, 0.0410923, 0.951091}, {0.612005, 0.79881, 0.819404,  0.183304, 0.320483, 0.473042, 0.939852, 0.230818, 0.859383,  0.408347, 0.679037, 0.425345, 0.202651, 0.249956,  0.732051}, {0.118409, 0.534995, 0.570928, 0.854301,  0.0871443}, {{1, 1, 1}, {2, 1, 1}, {3, 2, 1}, {0, 2, 3}, {3, 0,  3}, {3, 0, 1}, {3, 1, 4}, {0, 1, 2}}, 0.64436, 0.568243,  0.813209, 0.136053, 0.0323545, 0.769433, 0.993805, 0.952749,  0.711872, 0.296391, 0.053953,  0.721931}, -131.385}, {{0.852489, {0.888045, 0.374916,  0.296586}, {0.649838, 0.638089, 0.642865, 0.178177, 0.114842,  0.0671607, 0.788564, 0.0910322, 0.470482, 0.498917, 0.975356,  0.954979, 0.438128, 0.729484, 0.981551, 0.00223012}, {0.726256,  0.433093, 0.927598, 0.280299}, {0.873767, 0.545048, 0.552681,  0.983713, 0.22393, 0.90696, 0.909816, 0.805537, 0.109088,  0.839799, 0.121252, 0.714505, 0.638605, 0.340882,  0.145896}, {0.759526, 0.200477, 0.611397, 0.164345,  0.757296}, {{3, 2, 1}, {2, 1, 1}, {2, 2, 3}, {2, 1, 1}, {3, 0,  2}, {3, 2, 2}, {1, 2, 0}, {2, 2, 1}}, 0.474221, 0.178305,  0.236748, 0.476996, 0.600454, 0.633256, 0.684067, 0.493283,  0.376524, 0.726297, 0.774251,  0.687746}, -137.106}, {{0.267437, {0.886498, 0.652999,  0.973241}, {0.628831, 0.545616, 0.507103, 0.213715, 0.428354,  0.934218, 0.342758, 0.45642, 0.954133, 0.755914, 0.10601,  0.979424, 0.353679, 0.122657, 0.421943, 0.486141}, {0.977155,  0.396361, 0.647693, 0.798395}, {0.709718, 0.509863, 0.994694,  0.825154, 0.0808868, 0.964247, 0.487591, 0.611439, 0.652533,  0.0300292, 0.144833, 0.155019, 0.6984, 0.274115,  0.0388231}, {0.175596, 0.344721, 0.151458, 0.61688,  0.689455}, {{3, 0, 4}, {0, 0, 1}, {3, 2, 3}, {0, 2, 1}, {3, 2,  2}, {3, 2, 2}, {3, 2, 0}, {0, 2, 3}}, 0.367566, 0.755097,  0.969187, 0.891059, 0.657848, 0.245234, 0.974493, 0.0659051,  0.576961, 0.280987, 0.486902, 0.454466}, -146.014}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      ParameterizedNormalDistribution priorlogalpha = 
        parameterized_normal_distribution (data[i].input.priorlogalphavar);

      ParameterizedNormalDistribution priortau =
        parameterized_normal_distribution (data[i].input.priortauvar);

      NormalDistribution priorgammanormal[4] = {
          normal_distribution (data[i].input.priorgamma1mean,
                               data[i].input.priorgamma1var),
          normal_distribution (data[i].input.priorgamma2mean,
                               data[i].input.priorgamma2var),
          normal_distribution (data[i].input.priorgamma3mean,
                               data[i].input.priorgamma3var),
          normal_distribution (data[i].input.priorgamma4mean,
                               data[i].input.priorgamma4var)
      };

      Distribution* priorgamma[4] = {
          &priorgammanormal[0].base,
          &priorgammanormal[1].base,
          &priorgammanormal[2].base,
          &priorgammanormal[3].base
      };

      NormalDistribution priorkappa = 
        normal_distribution (data[i].input.priorkappamean,
                             data[i].input.priorkappavar);


      double q = qfunc (data[i].input.kappa,
                        data[i].input.logalpha,
                        4,
                        5,
                        data[i].input.tau,
                        3,
                        data[i].input.gamma,
                        data[i].input.pz,
                        data[i].input.priorz,
                        data[i].input.ratings,
                        8,
                        &priorkappa.base,
                        &priorlogalpha.base,
                        &priortau.base,
                        priorgamma);

      assert (      fabs (q - data[i].output) 
                 <= 1e-5 * (1 + fabs (q) + fabs (data[i].output))
              || (fprintf (stderr, "fail: %g != %g\n", q, data[i].output),
                  0));
    }
}

static void
test_dqfuncdkappa (void)
{
  QfuncTestDatum data[] = 
    {{{0.0261571, {0.605211, 0.576957, 0.794383}, {0.178832, 0.627307,  0.292979, 0.54762, 0.929124, 0.393839, 0.672606, 0.247274,  0.964635, 0.433123, 0.895675, 0.178499, 0.321753, 0.036564,  0.988933, 0.373979}, {0.280467, 0.0104809, 0.0479433,  0.929337}, {0.25431, 0.40527, 0.470986, 0.134954, 0.0754777,  0.777963, 0.178008, 0.587334, 0.146354, 0.384124, 0.505402,  0.34006, 0.181719, 0.951002, 0.609727}, {0.161561, 0.859966,  0.914438, 0.620794,  0.787582}, {{3, 1, 1}, {1, 0, 2}, {1, 0, 0}, {2, 0, 0}, {2, 2,  4}, {2, 2, 2}, {0, 0, 1}, {1, 1, 1}}, 0.579499, 0.903957,  0.572851, 0.858245, 0.325188, 0.498686, 0.101864, 0.723291,  0.249711, 0.720723, 0.923857, 0.135957},  54.2178}, {{0.103357, {0.336599, 0.418454, 0.795897}, {0.921638,  0.385597, 0.808727, 0.634336, 0.0616723, 0.47116, 0.187933,  0.846754, 0.482174, 0.567203, 0.615083, 0.988509, 0.156985,  0.0685165, 0.513218, 0.265219}, {0.907275, 0.347793, 0.589362,  0.129262}, {0.803918, 0.0111946, 0.170908, 0.333365, 0.88228,  0.625597, 0.36218, 0.699029, 0.820607, 0.154438, 0.174247,  0.852275, 0.338434, 0.587235, 0.559164}, {0.863765, 0.181448,  0.518718, 0.0459458,  0.598547}, {{1, 1, 1}, {2, 0, 1}, {1, 2, 0}, {2, 2, 4}, {3, 0,  4}, {0, 0, 1}, {2, 2, 1}, {3, 2, 1}}, 0.274174, 0.170925,  0.456584, 0.469285, 0.470256, 0.15973, 0.285676, 0.13592, 0.587977,  0.534133, 0.923496, 0.436891},  20.8041}, {{0.767369, {0.379695, 0.749249, 0.584616}, {0.428936,  0.79246, 0.190085, 0.720851, 0.247487, 0.273742, 0.144139,  0.122304, 0.973314, 0.102817, 0.687555, 0.653019, 0.503058,  0.943086, 0.401879, 0.517099}, {0.915081, 0.408953, 0.478383,  0.0802088}, {0.147712, 0.0292581, 0.729134, 0.495593, 0.718776,  0.236798, 0.539049, 0.774742, 0.471289, 0.963056, 0.39491,  0.652438, 0.497975, 0.860239, 0.707355}, {0.999419, 0.994918,  0.917152, 0.305476,  0.48232}, {{3, 2, 0}, {0, 0, 2}, {3, 0, 0}, {2, 0, 0}, {0, 2,  0}, {2, 1, 1}, {2, 0, 1}, {1, 0, 4}}, 0.0798365, 0.508199,  0.827093, 0.402111, 0.932125, 0.478941, 0.0979593, 0.906518,  0.213348, 0.242143, 0.55891,  0.131776}, -104.342}, {{0.742059, {0.279088, 0.164,  0.479337}, {0.244084, 0.418849, 0.456645, 0.479918, 0.249167,  0.501696, 0.151168, 0.997599, 0.16933, 0.993497, 0.324075,  0.595488, 0.237205, 0.514556, 0.226116, 0.68897}, {0.023857,  0.272413, 0.667206, 0.557194}, {0.281798, 0.993325, 0.503206,  0.0778564, 0.0377133, 0.574476, 0.0465613, 0.597938, 0.788547,  0.07278, 0.895393, 0.60034, 0.619217, 0.0792829,  0.571318}, {0.00485191, 0.382011, 0.564727, 0.345202,  0.315882}, {{1, 2, 4}, {2, 0, 3}, {0, 2, 0}, {0, 0, 1}, {2, 0,  4}, {0, 2, 0}, {3, 1, 2}, {2, 0, 0}}, 0.358154, 0.292314,  0.677996, 0.758688, 0.0763569, 0.298989, 0.17479, 0.680832,  0.0386435, 0.724513, 0.128229,  0.0828939}, -99.4951}, {{0.250097, {0.651733, 0.232836,  0.482554}, {0.63088, 0.57245, 0.661518, 0.477702, 0.248869,  0.00772342, 0.316316, 0.16182, 0.890714, 0.715409, 0.638321,  0.403132, 0.814357, 0.41642, 0.463531, 0.7223}, {0.775714,  0.691907, 0.335302, 0.639406}, {0.525617, 0.0401734, 0.102467,  0.156852, 0.894737, 0.467723, 0.440948, 0.679149, 0.645868, 0.46,  0.124632, 0.517329, 0.755154, 0.744591, 0.486311}, {0.114197,  0.940797, 0.328171, 0.0227806,  0.391897}, {{0, 2, 4}, {2, 1, 2}, {2, 0, 2}, {1, 2, 4}, {3, 2,  0}, {2, 1, 1}, {3, 0, 2}, {3, 1, 3}}, 0.165083, 0.636264,  0.687478, 0.752492, 0.639466, 0.596091, 0.585012, 0.59564,  0.744729, 0.128368, 0.144064, 0.916491},  22.5078}, {{0.0988603, {0.668368, 0.0194316, 0.399162}, {0.343706,  0.923777, 0.53312, 0.284965, 0.402909, 0.595607, 0.51034,  0.893067, 0.237826, 0.959342, 0.822861, 0.140576, 0.59836,  0.363252, 0.237849, 0.544936}, {0.853632, 0.234884, 0.0937858,  0.628445}, {0.754771, 0.566516, 0.0743543, 0.229283, 0.411065,  0.642738, 0.541234, 0.944318, 0.00815595, 0.0471319, 0.0308945,  0.0512503, 0.77033, 0.0877895, 0.208033}, {0.910674, 0.171969,  0.724538, 0.970184,  0.365739}, {{3, 2, 2}, {2, 0, 4}, {3, 2, 4}, {0, 0, 2}, {2, 2,  1}, {0, 0, 4}, {0, 1, 0}, {3, 2, 4}}, 0.318338, 0.489654,  0.876398, 0.737294, 0.563567, 0.923138, 0.802044, 0.508011,  0.152501, 0.2804, 0.26081, 0.563694},  8.30905}, {{0.144346, {0.233268, 0.229915, 0.512443}, {0.374016,  0.145479, 0.0218821, 0.601769, 0.202046, 0.420941, 0.0516981,  0.23603, 0.883708, 0.931286, 0.1753, 0.498736, 0.320142, 0.008148,  0.373256, 0.990725}, {0.16764, 0.727748, 0.112446,  0.427031}, {0.0232948, 0.49448, 0.882531, 0.914588, 0.649279,  0.349001, 0.860649, 0.312819, 0.447233, 0.928061, 0.808951,  0.0767885, 0.563524, 0.996775, 0.633651}, {0.578052, 0.243382,  0.988627, 0.260395,  0.587327}, {{0, 1, 2}, {3, 2, 0}, {0, 0, 3}, {0, 1, 3}, {2, 0,  2}, {2, 2, 4}, {1, 2, 0}, {2, 0, 4}}, 0.0757419, 0.260878,  0.147948, 0.160296, 0.0524471, 0.766398, 0.265417, 0.245709,  0.403168, 0.417397, 0.404769, 0.93289},  94.8792}, {{0.955936, {0.489336, 0.595818, 0.856101}, {0.392411,  0.492562, 0.962167, 0.278049, 0.149029, 0.503935, 0.701773,  0.690722, 0.0732871, 0.243057, 0.553824, 0.530425, 0.02084,  0.476658, 0.288407, 0.284717}, {0.617672, 0.0592612, 0.883638,  0.351827}, {0.661736, 0.569925, 0.28782, 0.495726, 0.269325,  0.0773633, 0.325653, 0.217676, 0.120296, 0.573428, 0.62388,  0.526955, 0.0470088, 0.330371, 0.0700562}, {0.996529, 0.0261688,  0.853713, 0.781649,  0.711812}, {{0, 2, 1}, {1, 2, 4}, {3, 1, 4}, {1, 1, 2}, {3, 0,  4}, {2, 1, 0}, {2, 1, 0}, {3, 0, 2}}, 0.408497, 0.794452,  0.898011, 0.359985, 0.746761, 0.224527, 0.610191, 0.86426,  0.477436, 0.147164, 0.284538,  0.646584}, -7.15848}, {{0.35714, {0.573736, 0.660657,  0.119629}, {0.310131, 0.243364, 0.590601, 0.1231, 0.283962,  0.389651, 0.808952, 0.411287, 0.875465, 0.595199, 0.910941,  0.0513018, 0.128705, 0.370672, 0.30075, 0.187042}, {0.651269,  0.223508, 0.0162116, 0.540458}, {0.294129, 0.649772, 0.355554,  0.420829, 0.983998, 0.406408, 0.764953, 0.29773, 0.700036,  0.0167573, 0.956001, 0.886442, 0.824571, 0.421558,  0.0450606}, {0.83514, 0.695866, 0.0508867, 0.744311,  0.648099}, {{1, 1, 1}, {0, 2, 0}, {2, 2, 2}, {3, 2, 2}, {1, 0,  1}, {3, 2, 1}, {2, 1, 0}, {1, 1, 2}}, 0.0445975, 0.827379,  0.728099, 0.10764, 0.750468, 0.177606, 0.372545, 0.686811, 0.76647,  0.771198, 0.607592, 0.389081},  143.742}, {{0.0664334, {0.754441, 0.651591, 0.502639}, {0.241862,  0.332883, 0.606531, 0.667499, 0.545996, 0.281996, 0.86222,  0.0194002, 0.501398, 0.454617, 0.13412, 0.91176, 0.75093,  0.277011, 0.761575, 0.224949}, {0.984461, 0.505812, 0.153983,  0.835868}, {0.918027, 0.751371, 0.502392, 0.333229, 0.676165,  0.418489, 0.895861, 0.66573, 0.130169, 0.136493, 0.0336415,  0.64633, 0.62877, 0.681876, 0.899521}, {0.73457, 0.87784,  0.404865, 0.137946,  0.509621}, {{1, 2, 1}, {2, 0, 4}, {2, 1, 2}, {1, 2, 3}, {1, 2, 0},  {2, 0, 4}, {3, 1, 1}, {0, 1, 3}}, 0.89338, 0.899053, 0.983964,  0.673753, 0.975353, 0.147682, 0.481572, 0.340524, 0.299188,  0.729193, 0.585711, 0.674794}, 3.28213}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      ParameterizedNormalDistribution priorlogalpha = 
        parameterized_normal_distribution (data[i].input.priorlogalphavar);

      ParameterizedNormalDistribution priortau =
        parameterized_normal_distribution (data[i].input.priortauvar);

      NormalDistribution priorgammanormal[4] = {
          normal_distribution (data[i].input.priorgamma1mean,
                               data[i].input.priorgamma1var),
          normal_distribution (data[i].input.priorgamma2mean,
                               data[i].input.priorgamma2var),
          normal_distribution (data[i].input.priorgamma3mean,
                               data[i].input.priorgamma3var),
          normal_distribution (data[i].input.priorgamma4mean,
                               data[i].input.priorgamma4var)
      };

      Distribution* priorgamma[4] = {
          &priorgammanormal[0].base,
          &priorgammanormal[1].base,
          &priorgammanormal[2].base,
          &priorgammanormal[3].base
      };

      NormalDistribution priorkappa = 
        normal_distribution (data[i].input.priorkappamean,
                             data[i].input.priorkappavar);


      double dkappa;
      double dlogalpha[3];
      double dtau[4*(5-1)];
      double dgamma[(5-1)];

      dqfunc (&dkappa,
              dlogalpha,
              dtau,
              dgamma,
              data[i].input.kappa,
              data[i].input.logalpha,
              4,
              5,
              data[i].input.tau,
              3,
              data[i].input.gamma,
              data[i].input.pz,
              data[i].input.ratings,
              8,
              &priorkappa.base,
              &priorlogalpha.base,
              &priortau.base,
              priorgamma);

      assert (      fabs (dkappa - data[i].output) 
                 <= 1e-5 * (1 + fabs (dkappa) + fabs (data[i].output))
              || (fprintf (stderr, "fail: %g != %g\n", dkappa, data[i].output),
                  0));
    }
}

typedef struct _DQfuncDlogalphaTestDatum DQfuncDlogalphaTestDatum;
struct _DQfuncDlogalphaTestDatum
{
  struct
    {
      double kappa;
      double logalpha[3];
      double tau[4*(5-1)];
      double gamma[(5-1)];
      double pz[3*5];
      double priorz[5];
      Rating ratings[8];
      double priorlogalphavar;
      double priortauvar;
      double priorgamma1mean;
      double priorgamma1var;
      double priorgamma2mean;
      double priorgamma2var;
      double priorgamma3mean;
      double priorgamma3var;
      double priorgamma4mean;
      double priorgamma4var;
      double priorkappamean;
      double priorkappavar;
    }                           input;

  double                        dlogalpha[3];
};

static void
test_dqfuncdlogalpha (void)
{
  DQfuncDlogalphaTestDatum data[] = 
    {{{0.87184, {0.791302, 0.0912192, 0.674918}, {0.842148, 0.636415,  0.183016, 0.85828, 0.191522, 0.760656, 0.40777, 0.783495,  0.681842, 0.583048, 0.145672, 0.12053, 0.253693, 0.583293,  0.997559, 0.0144895}, {0.202924, 0.53688, 0.840344,  0.445169}, {0.331084, 0.745579, 0.749125, 0.770251, 0.488937,  0.109164, 0.566109, 0.911972, 0.297415, 0.348508, 0.15834,  0.128477, 0.615573, 0.76546, 0.0126681}, {0.0079464, 0.36188,  0.182167, 0.015109,  0.993457}, {{0, 1, 4}, {3, 0, 0}, {0, 1, 4}, {0, 0, 1}, {1, 0,  3}, {0, 0, 4}, {0, 2, 2}, {1, 0, 2}}, 0.158956, 0.645286,  0.174765, 0.548288, 0.827871, 0.899708, 0.42564, 0.778037,  0.338935, 0.790544, 0.85953, 0.866065}, {-108.037,  31.8806, -3.78992}}, {{0.0415198, {0.442037, 0.701191,  0.737589}, {0.425947, 0.676577, 0.688523, 0.729642, 0.0640672,  0.49441, 0.673414, 0.736185, 0.905111, 0.849124, 0.498649,  0.187897, 0.0772399, 0.949416, 0.0730094, 0.40986}, {0.738305,  0.158871, 0.213479, 0.543795}, {0.696785, 0.716835, 0.512288,  0.806206, 0.270838, 0.0402583, 0.823766, 0.076564, 0.206771,  0.545848, 0.150352, 0.340379, 0.30166, 0.696725,  0.651703}, {0.152481, 0.22442, 0.747309, 0.578694,  0.742621}, {{3, 2, 4}, {1, 0, 3}, {0, 2, 0}, {1, 0, 3}, {0, 0,  0}, {2, 2, 4}, {3, 1, 3}, {3, 0, 2}}, 0.486115, 0.588438,  0.365215, 0.198826, 0.789329, 0.871603, 0.852926, 0.392619,  0.518491, 0.831344, 0.0291604,  0.316055}, {-51.1877, -8.70799, -39.9672}}, {{0.31172, {0.285496,  0.878808, 0.975677}, {0.0100601, 0.588771, 0.227105, 0.823195,  0.78564, 0.841462, 0.648411, 0.0805746, 0.299526, 0.253025,  0.283196, 0.881749, 0.510197, 0.381422, 0.43027,  0.48913}, {0.991706, 0.550077, 0.401109, 0.173075}, {0.679986,  0.264581, 0.522301, 0.197398, 0.669926, 0.67581, 0.295196,  0.374203, 0.884285, 0.834348, 0.646786, 0.293628, 0.584759,  0.581323, 0.36359}, {0.411879, 0.0745629, 0.199901, 0.93332,  0.922749}, {{1, 0, 4}, {1, 0, 0}, {3, 2, 0}, {0, 0, 3}, {3, 2,  1}, {2, 2, 4}, {3, 2, 2}, {2, 1, 4}}, 0.0828573, 0.649824,  0.532211, 0.749675, 0.402872, 0.385243, 0.00991003, 0.552277,  0.732946, 0.709433, 0.714714,  0.178074}, {-20.4532, -84.8392, -191.795}}, {{0.848661, {0.875085,  0.0679283, 0.884446}, {0.263901, 0.293762, 0.704339, 0.472567,  0.189339, 0.0938605, 0.771019, 0.549818, 0.106481, 0.444037,  0.238808, 0.800143, 0.70361, 0.0587941, 0.228898,  0.247866}, {0.970664, 0.349362, 0.514184, 0.0697916}, {0.122003,  0.474277, 0.446255, 0.185345, 0.858101, 0.180515, 0.741917,  0.712778, 0.668763, 0.0866545, 0.970898, 0.162961, 0.562281,  0.642618, 0.732091}, {0.362818, 0.858672, 0.583824, 0.503193,  0.114952}, {{3, 1, 0}, {0, 1, 1}, {1, 2, 3}, {2, 0, 4}, {0, 1,  4}, {2, 0, 0}, {0, 2, 4}, {2, 0, 4}}, 0.888008, 0.234462,  0.989009, 0.0451604, 0.766006, 0.760186, 0.542754, 0.859815,  0.907904, 0.579671, 0.800837,  0.147037}, {-43.9555, -24.1469, -17.5132}}, {{0.239142, {0.493016,  0.829939, 0.984076}, {0.67686, 0.850398, 0.0978481, 0.621258,  0.818188, 0.266574, 0.594655, 0.506306, 0.93018, 0.0321123,  0.605646, 0.461146, 0.164174, 0.271927, 0.0628918,  0.601331}, {0.25627, 0.692256, 0.262055, 0.454294}, {0.0171281,  0.19924, 0.432116, 0.470218, 0.340268, 0.348842, 0.334268,  0.84896, 0.52208, 0.0822675, 0.739613, 0.342653, 0.5919,  0.0501552, 0.133967}, {0.881507, 0.427725, 0.778228, 0.0710756,  0.280176}, {{1, 0, 1}, {3, 0, 4}, {3, 1, 4}, {0, 0, 1}, {1, 2,  4}, {3, 1, 0}, {3, 2, 2}, {0, 1, 4}}, 0.171455, 0.0859723,  0.809021, 0.825882, 0.154327, 0.886732, 0.376905, 0.355664,  0.814059, 0.53789, 0.0426366,  0.506705}, {-38.6787, -53.0184, -39.3243}}, {{0.29198, {0.455623,  0.303024, 0.164051}, {0.70008, 0.405467, 0.169056, 0.282544,  0.272355, 0.627239, 0.0979806, 0.00236737, 0.1009, 0.541267,  0.28896, 0.176485, 0.946572, 0.654535, 0.912055,  0.820821}, {0.132513, 0.116644, 0.869419, 0.314116}, {0.840533,  0.661022, 0.566395, 0.150065, 0.140453, 0.255554, 0.397339,  0.867521, 0.868098, 0.628315, 0.299358, 0.865154, 0.767199,  0.0870486, 0.0103985}, {0.688669, 0.820626, 0.432514, 0.0983432,  0.867848}, {{0, 1, 4}, {2, 2, 0}, {0, 0, 2}, {2, 1, 4}, {2, 2,  3}, {3, 2, 0}, {2, 0, 4}, {0, 2, 4}}, 0.688113, 0.31587,  0.228924, 0.553732, 0.84758, 0.654848, 0.662529, 0.403667,  0.707127, 0.399294, 0.26519, 0.536146}, {-9.19098,  0.401293, -16.3347}}, {{0.839029, {0.770978, 0.965832,  0.670992}, {0.0718303, 0.68393, 0.955434, 0.982323, 0.251204,  0.251416, 0.85709, 0.114475, 0.563091, 0.935546, 0.628166,  0.560744, 0.715511, 0.280698, 0.965637, 0.157077}, {0.00838377,  0.881404, 0.700446, 0.620931}, {0.169355, 0.110426, 0.734614,  0.949939, 0.0975246, 0.426496, 0.779181, 0.967616, 0.846321,  0.175081, 0.92209, 0.853141, 0.28323, 0.239534,  0.293924}, {0.292397, 0.567719, 0.958836, 0.328288,  0.13532}, {{0, 1, 4}, {0, 1, 2}, {1, 2, 3}, {3, 0, 1}, {0, 1,  1}, {0, 2, 4}, {1, 1, 4}, {0, 1, 4}}, 0.559335, 0.0774318,  0.627841, 0.514389, 0.38998, 0.967006, 0.893227, 0.56445, 0.292456,  0.540509, 0.114047,  0.596834}, {-25.3375, -51.6055, -11.4048}}, {{0.446135, {0.365429,  0.191957, 0.743693}, {0.162905, 0.125894, 0.898032, 0.451296,  0.595187, 0.167058, 0.569745, 0.315976, 0.0358513, 0.0896263,  0.941903, 0.801587, 0.645871, 0.122621, 0.0486761,  0.237137}, {0.353415, 0.582111, 0.934629, 0.640303}, {0.90728,  0.216682, 0.742673, 0.89661, 0.744375, 0.0907877, 0.84464,  0.445313, 0.149188, 0.92373, 0.274895, 0.129337, 0.113337,  0.834103, 0.332992}, {0.32775, 0.467466, 0.711483, 0.284316,  0.0906133}, {{1, 0, 3}, {2, 2, 0}, {1, 0, 4}, {1, 2, 3}, {0, 2,  1}, {3, 0, 0}, {2, 1, 1}, {3, 0, 4}}, 0.11405, 0.129371,  0.349687, 0.45031, 0.20677, 0.912689, 0.607014, 0.553701, 0.462396,  0.821902, 0.762374, 0.108388}, {-43.2569,  4.02173, -82.7619}}, {{0.313208, {0.898172, 0.487478,  0.97905}, {0.199871, 0.0640689, 0.154487, 0.6513, 0.732405,  0.352586, 0.870171, 0.560687, 0.618355, 0.223215, 0.520484,  0.110376, 0.411585, 0.310526, 0.91347, 0.556676}, {0.949189,  0.488624, 0.151096, 0.448288}, {0.635981, 0.590452, 0.663618,  0.469237, 0.43611, 0.526383, 0.509131, 0.817937, 0.703704,  0.173797, 0.638961, 0.25725, 0.0853494, 0.950582,  0.118477}, {0.146874, 0.673765, 0.640056, 0.205006,  0.590198}, {{2, 1, 0}, {2, 0, 1}, {0, 0, 2}, {2, 0, 2}, {1, 2,  3}, {3, 1, 2}, {2, 2, 0}, {1, 1, 2}}, 0.724576, 0.151432,  0.0539102, 0.14191, 0.0885952, 0.560981, 0.390292, 0.672673,  0.652485, 0.0345977, 0.881161,  0.854736}, {-76.9741, -48.2058, -46.0665}}, {{0.948781, {0.860801,  0.242201, 0.597485}, {0.863432, 0.91022, 0.123724, 0.450612,  0.189667, 0.270163, 0.918718, 0.860413, 0.465091, 0.118731,  0.864807, 0.718503, 0.376495, 0.55775, 0.474515,  0.0458298}, {0.72401, 0.523153, 0.593354, 0.191094}, {0.775229,  0.662352, 0.351153, 0.593609, 0.911798, 0.752132, 0.227429,  0.142997, 0.722131, 0.481969, 0.308712, 0.282584, 0.25704,  0.363238, 0.443904}, {0.564081, 0.880545, 0.805487, 0.969389,  0.518251}, {{3, 2, 0}, {0, 2, 1}, {3, 2, 2}, {3, 2, 3}, {3, 2,  4}, {1, 1, 0}, {2, 0, 2}, {0, 0, 4}}, 0.156535, 0.282335,  0.376036, 0.327157, 0.381306, 0.619983, 0.0248823, 0.733548,  0.469508, 0.867851, 0.797453, 0.590551}, {-23.064,  10.4404, -44.4564}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      ParameterizedNormalDistribution priorlogalpha = 
        parameterized_normal_distribution (data[i].input.priorlogalphavar);

      ParameterizedNormalDistribution priortau =
        parameterized_normal_distribution (data[i].input.priortauvar);

      NormalDistribution priorgammanormal[4] = {
          normal_distribution (data[i].input.priorgamma1mean,
                               data[i].input.priorgamma1var),
          normal_distribution (data[i].input.priorgamma2mean,
                               data[i].input.priorgamma2var),
          normal_distribution (data[i].input.priorgamma3mean,
                               data[i].input.priorgamma3var),
          normal_distribution (data[i].input.priorgamma4mean,
                               data[i].input.priorgamma4var)
      };

      Distribution* priorgamma[4] = {
          &priorgammanormal[0].base,
          &priorgammanormal[1].base,
          &priorgammanormal[2].base,
          &priorgammanormal[3].base
      };

      NormalDistribution priorkappa = 
        normal_distribution (data[i].input.priorkappamean,
                             data[i].input.priorkappavar);

      double dkappa;
      double dlogalpha[3];
      double dtau[4*(5-1)];
      double dgamma[(5-1)];

      dqfunc (&dkappa,
              dlogalpha,
              dtau,
              dgamma,
              data[i].input.kappa,
              data[i].input.logalpha,
              4,
              5,
              data[i].input.tau,
              3,
              data[i].input.gamma,
              data[i].input.pz,
              data[i].input.ratings,
              8,
              &priorkappa.base,
              &priorlogalpha.base,
              &priortau.base,
              priorgamma);

      for (unsigned int j = 0; j < 3; ++j)
        {
          assert (      fabs (dlogalpha[j] - data[i].dlogalpha[j]) 
                     <= 1e-4 * (1 + fabs (dlogalpha[j]) + fabs (data[i].dlogalpha[j]))
                  || (fprintf (stderr, "fail: %g != %g\n", dlogalpha[j], data[i].dlogalpha[j]),
                      0));
        }
    }
}

typedef struct _DQfuncDtauTestDatum DQfuncDtauTestDatum;
struct _DQfuncDtauTestDatum
{
  struct
    {
      double kappa;
      double logalpha[3];
      double tau[4*(5-1)];
      double gamma[(5-1)];
      double pz[3*5];
      double priorz[5];
      Rating ratings[8];
      double priorlogalphavar;
      double priortauvar;
      double priorgamma1mean;
      double priorgamma1var;
      double priorgamma2mean;
      double priorgamma2var;
      double priorgamma3mean;
      double priorgamma3var;
      double priorgamma4mean;
      double priorgamma4var;
      double priorkappamean;
      double priorkappavar;
    }                           input;

  double                        dtau[4*(5-1)];
};

static void
test_dqfuncdtau (void)
{
  DQfuncDtauTestDatum data[] = 
    {{{0.498011, {0.949291, 0.166333, 0.0912673}, {0.802303, 0.304656,  0.100281, 0.0436587, 0.828242, 0.217476, 0.942903, 0.885643,  0.168336, 0.662666, 0.409, 0.747054, 0.17003, 0.436445, 0.481426,  0.0546134}, {0.482446, 0.221517, 0.711673, 0.633453}, {0.984435,  0.272226, 0.54534, 0.542185, 0.182132, 0.967569, 0.445059,  0.498527, 0.353889, 0.750093, 0.502156, 0.612883, 0.185553,  0.0874275, 0.0931559}, {0.865829, 0.015524, 0.650982, 0.61173,  0.811215}, {{1, 0, 4}, {3, 2, 3}, {0, 2, 0}, {1, 1, 3}, {3, 0,  2}, {3, 0, 4}, {2, 2, 3}, {0, 1, 2}}, 0.533078, 0.429465,  0.900057, 0.177763, 0.548643, 0.157239, 0.354717, 0.635577,  0.366512, 0.18967, 0.909659, 0.13705}, {-0.929582, -0.000650651,  7.00451, 6.33413, -4.70514, -3.37871, -5.33396, -2.55791,  1.46244, -2.88221, 0.953376, 0.0147909, -1.1, -5.83292, 2.35951,  5.36467}}, {{0.0126224, {0.439577, 0.407503, 0.524167}, {0.827069,  0.352149, 0.314347, 0.658338, 0.811545, 0.701167, 0.702617,  0.847123, 0.278467, 0.271702, 0.80256, 0.669361, 0.729823,  0.114463, 0.447843, 0.0337833}, {0.363311, 0.924793, 0.538184,  0.896733}, {0.350689, 0.485216, 0.130681, 0.372566, 0.52362,  0.133067, 0.816334, 0.714227, 0.712075, 0.4319, 0.113717,  0.867104, 0.433609, 0.160198, 0.311157}, {0.197743, 0.703786,  0.0457355, 0.863314,  0.16396}, {{0, 0, 2}, {3, 1, 3}, {3, 0, 3}, {2, 2, 1}, {1, 0,  3}, {3, 1, 3}, {1, 0, 0}, {0, 0, 4}}, 0.340474, 0.120943,  0.32513, 0.267227, 0.989785, 0.635726, 0.194449, 0.894662,  0.466165, 0.502659, 0.378115, 0.180435}, {-32.4427, 38.1618,  16.9324, 17.3151, -28.6438, 16.9039, -9.97268, 6.99921, 5.68704,  47.5828, -15.4663, 17.6754, -25.6024, 54.6269, 5.01977,  68.4116}}, {{0.754089, {0.0707586, 0.264398, 0.313331}, {0.320481,  0.91056, 0.953241, 0.115587, 0.616695, 0.864825, 0.089927,  0.951627, 0.276221, 0.743882, 0.764797, 0.6844, 0.286436,  0.108156, 0.570348, 0.789738}, {0.820271, 0.605497, 0.192233,  0.609303}, {0.0661818, 0.534739, 0.927835, 0.295973, 0.745701,  0.624178, 0.974594, 0.180385, 0.129006, 0.759353, 0.884667,  0.228758, 0.852785, 0.015471, 0.11987}, {0.544358, 0.566349,  0.907315, 0.549522,  0.75462}, {{0, 1, 1}, {1, 1, 1}, {1, 0, 0}, {3, 1, 1}, {3, 2,  4}, {3, 1, 1}, {2, 2, 3}, {1, 2, 4}}, 0.746078, 0.301818,  0.357289, 0.145317, 0.679896, 0.767079, 0.429453, 0.849344,  0.934195, 0.142901, 0.454859,  0.668959}, {5.00349, -0.799443, -6.08274, 7.43714, 3.65634,  1.29905, 4.80379, -1.58486, 5.36779, -2.57313, -7.57224, 0.470388,  4.72569, 10.379, -0.422566,  0.229303}}, {{0.805189, {0.383548, 0.570191, 0.440201}, {0.952404,  0.368077, 0.450321, 0.895843, 0.386055, 0.460762, 0.900799,  0.141222, 0.639977, 0.158944, 0.54351, 0.995905, 0.960081,  0.391865, 0.114057, 0.146561}, {0.0258867, 0.248964, 0.659198,  0.477602}, {0.220698, 0.865416, 0.0890069, 0.0374008, 0.268294,  0.497339, 0.638686, 0.141558, 0.882239, 0.0365775, 0.737887,  0.000335617, 0.242262, 0.877633, 0.194376}, {0.00443016, 0.282181,  0.485769, 0.0803192,  0.857869}, {{2, 1, 1}, {3, 2, 4}, {0, 2, 4}, {0, 1, 0}, {3, 0,  3}, {1, 1, 0}, {3, 1, 0}, {2, 0, 0}}, 0.256294, 0.236805,  0.421121, 0.380267, 0.0355962, 0.371389, 0.332114, 0.342866,  0.767302, 0.874049, 0.693428, 0.201308}, {-14.1403, -0.0962319,  5.42619, -6.41475, -3.04231, -0.695498, -1.47578,  8.62503, -9.53961, 6.55161, 6.39257, -5.99175, -14.3909, -0.654753,  11.3264,  9.02105}}, {{0.885062, {0.837472, 0.955542, 0.200973}, {0.6428,  0.959839, 0.761165, 0.196543, 0.360619, 0.47407, 0.680846,  0.338674, 0.104325, 0.237265, 0.259725, 0.958406, 0.0687287,  0.865876, 0.927611, 0.61554}, {0.301427, 0.991827, 0.234183,  0.414231}, {0.416364, 0.154355, 0.278641, 0.213258, 0.773564,  0.194516, 0.517476, 0.0167158, 0.412945, 0.720446, 0.83663,  0.678042, 0.30862, 0.483181, 0.576905}, {0.719636, 0.239892,  0.617305, 0.649294,  0.104096}, {{0, 2, 4}, {0, 2, 0}, {0, 0, 3}, {3, 0, 1}, {1, 2,  0}, {2, 1, 3}, {2, 0, 4}, {3, 2, 4}}, 0.938465, 0.625478,  0.41511, 0.689865, 0.5221, 0.471123, 0.136469, 0.476607, 0.748536,  0.276607, 0.618993, 0.459891}, {0.535119, 0.529452, -1.35252,  4.25152, 2.89158, 4.00782, 1.24357, 2.24844, -0.0909209,  0.856327, -1.51285, 1.05239, -0.36881, 2.60344, 0.068977,  0.897232}}, {{0.335591, {0.55616, 0.782363, 0.781848}, {0.0269708,  0.0729789, 0.205458, 0.0622124, 0.787079, 0.455674, 0.556164,  0.958116, 0.848614, 0.830196, 0.141054, 0.268251, 0.326514,  0.359073, 0.00458486, 0.791644}, {0.577978, 0.082466, 0.385592,  0.331754}, {0.242387, 0.526306, 0.603229, 0.549905, 0.215416,  0.453327, 0.397772, 0.487693, 0.428337, 0.997653, 0.841607,  0.529577, 0.579722, 0.167457, 0.700554}, {0.261326, 0.253208,  0.808384, 0.695969,  0.469681}, {{1, 2, 2}, {0, 2, 0}, {3, 0, 3}, {2, 1, 2}, {1, 2,  1}, {3, 0, 2}, {3, 0, 2}, {2, 1, 2}}, 0.675231, 0.725918,  0.310377, 0.137928, 0.432844, 0.199612, 0.707147, 0.588022,  0.217428, 0.746286, 0.309375, 0.10033}, {6.70991, 5.21153, 5.11349,  4.88061, -3.3628, 1.86616, 7.87989, 5.84157, -2.17176, -3.36236,  10.527, 9.82289, -0.106207, -1.48771, 6.85259,  7.3859}}, {{0.789092, {0.748633, 0.467768, 0.570753}, {0.20937,  0.581176, 0.767214, 0.309427, 0.956161, 0.772792, 0.0712457,  0.839746, 0.280931, 0.0468736, 0.760869, 0.701819, 0.848086,  0.847261, 0.053722, 0.113796}, {0.630658, 0.100975, 0.744347,  0.0134665}, {0.841566, 0.352342, 0.276579, 0.442713, 0.632197,  0.771166, 0.509364, 0.133286, 0.676036, 0.998375, 0.438118,  0.29354, 0.395105, 0.951501, 0.677249}, {0.591721, 0.547019,  0.10424, 0.623527,  0.477925}, {{2, 2, 0}, {2, 0, 3}, {2, 1, 3}, {2, 0, 4}, {2, 0,  1}, {0, 2, 3}, {0, 0, 0}, {1, 2, 3}}, 0.916361, 0.00326465,  0.879181, 0.464458, 0.0747943, 0.650922, 0.602602, 0.0217447,  0.442598, 0.879756, 0.093238,  0.888459}, {39532.1, -45052.5, -2142.87, -27761.7, -30541.5, -63035.1, 63154., -77523.3, 32815.3,  5081.16, -1547.63, -64574.6, -20400.5, -70021.5,  64799., -9413.58}}, {{0.766562, {0.881381, 0.65512,  0.594919}, {0.371457, 0.92988, 0.97787, 0.00319818, 0.824438,  0.82564, 0.354343, 0.525274, 0.908078, 0.822375, 0.475163,  0.0608155, 0.833283, 0.171453, 0.87256, 0.0390708}, {0.390686,  0.291697, 0.779322, 0.150612}, {0.624124, 0.410316, 0.124203,  0.555693, 0.252667, 0.480437, 0.146332, 0.552495, 0.428229,  0.654797, 0.791989, 0.0272212, 0.520151, 0.832422,  0.316827}, {0.966406, 0.686868, 0.660969, 0.444266,  0.927335}, {{0, 0, 3}, {0, 2, 1}, {1, 1, 4}, {0, 0, 2}, {2, 1,  3}, {2, 2, 0}, {0, 1, 2}, {0, 1, 0}}, 0.296182, 0.369271,  0.664944, 0.776723, 0.672058, 0.958955, 0.540741, 0.22103,  0.419391, 0.478518, 0.394409, 0.668535}, {0.354075, -1.97926,  9.8779, 16.8341, -3.91649, -4.81389,  2.1659, -3.84879, -1.16962, -1.62638, 4.40148, 7.0484, -3.24577,  0.881807, -0.683754,  0.817983}}, {{0.991162, {0.823722, 0.602419, 0.641314}, {0.471011,  0.9913, 0.285593, 0.674908, 0.784144, 0.330332, 0.841327,  0.747573, 0.487962, 0.96106, 0.176383, 0.97085, 0.815904,  0.00210532, 0.635642, 0.74982}, {0.396513, 0.523587, 0.241233,  0.0812852}, {0.405351, 0.699865, 0.638814, 0.439971, 0.93434,  0.708565, 0.353221, 0.765063, 0.150196, 0.378233, 0.511894,  0.0174901, 0.662235, 0.417173, 0.335511}, {0.0466399, 0.846331,  0.415068, 0.699869,  0.29682}, {{2, 1, 2}, {2, 2, 3}, {2, 1, 0}, {1, 2, 4}, {3, 1,  4}, {3, 0, 1}, {0, 0, 1}, {0, 0, 0}}, 0.449817, 0.891481,  0.458636, 0.215534, 0.0444663, 0.191616, 0.819822, 0.775563,  0.110126, 0.483051, 0.466601, 0.0104998}, {5.64143, 11.6287,  11.9349, 10.1716, -1.19531, -0.626078, -1.72794, -1.95525, 1.82269,  0.33473, 4.97602, 6.27503, -2.07782, 5.87806, 4.10218,  2.76623}}, {{0.95993, {0.104818, 0.954707, 0.99301}, {0.297695,  0.687645, 0.619196, 0.94637, 0.451365, 0.272577, 0.919326,  0.64955, 0.0015476, 0.381096, 0.46069, 0.434016, 0.957081,  0.18948, 0.640868, 0.658453}, {0.846955, 0.706429, 0.174267,  0.647953}, {0.887025, 0.601612, 0.219561, 0.654943, 0.589329,  0.913967, 0.600365, 0.708573, 0.137964, 0.64139, 0.681039,  0.0590231, 0.136417, 0.260294, 0.220348}, {0.625007, 0.179336,  0.070814, 0.57948,  0.966554}, {{0, 2, 1}, {0, 2, 0}, {1, 2, 2}, {1, 0, 4}, {3, 1,  0}, {3, 2, 4}, {2, 2, 2}, {3, 1, 4}}, 0.332381, 0.364385,  0.405212, 0.318601, 0.445356, 0.762773, 0.185652, 0.663658,  0.856026, 0.848805, 0.585287, 0.955085}, {5.39717, 3.97238,  0.268661, 1.17588, 1.24497, 0.824499, -4.96169, 0.234541, 5.62768,  0.973244, -0.240449, 3.41902, 1.16202,  5.3771, -2.64727, -0.224944}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      ParameterizedNormalDistribution priorlogalpha = 
        parameterized_normal_distribution (data[i].input.priorlogalphavar);

      ParameterizedNormalDistribution priortau =
        parameterized_normal_distribution (data[i].input.priortauvar);

      NormalDistribution priorgammanormal[4] = {
          normal_distribution (data[i].input.priorgamma1mean,
                               data[i].input.priorgamma1var),
          normal_distribution (data[i].input.priorgamma2mean,
                               data[i].input.priorgamma2var),
          normal_distribution (data[i].input.priorgamma3mean,
                               data[i].input.priorgamma3var),
          normal_distribution (data[i].input.priorgamma4mean,
                               data[i].input.priorgamma4var)
      };

      Distribution* priorgamma[4] = {
          &priorgammanormal[0].base,
          &priorgammanormal[1].base,
          &priorgammanormal[2].base,
          &priorgammanormal[3].base
      };

      NormalDistribution priorkappa = 
        normal_distribution (data[i].input.priorkappamean,
                             data[i].input.priorkappavar);

      double dkappa;
      double dlogalpha[3];
      double dtau[4*(5-1)];
      double dgamma[(5-1)];

      dqfunc (&dkappa,
              dlogalpha,
              dtau,
              dgamma,
              data[i].input.kappa,
              data[i].input.logalpha,
              4,
              5,
              data[i].input.tau,
              3,
              data[i].input.gamma,
              data[i].input.pz,
              data[i].input.ratings,
              8,
              &priorkappa.base,
              &priorlogalpha.base,
              &priortau.base,
              priorgamma);

      for (unsigned int j = 0; j < 4*(5-1); ++j)
        {
          assert (      fabs (dtau[j] - data[i].dtau[j]) 
                     <= 1e-4 * (1 + fabs (dtau[j]) + fabs (data[i].dtau[j]))
                  || (fprintf (stderr, "fail: %g != %g\n", dtau[j], data[i].dtau[j]),
                      0));
        }
    }
}

typedef struct _DQfuncDgammaTestDatum DQfuncDgammaTestDatum;
struct _DQfuncDgammaTestDatum
{
  struct
    {
      double kappa;
      double logalpha[3];
      double tau[4*(5-1)];
      double gamma[(5-1)];
      double pz[3*5];
      double priorz[5];
      Rating ratings[8];
      double priorlogalphavar;
      double priortauvar;
      double priorgamma1mean;
      double priorgamma1var;
      double priorgamma2mean;
      double priorgamma2var;
      double priorgamma3mean;
      double priorgamma3var;
      double priorgamma4mean;
      double priorgamma4var;
      double priorkappamean;
      double priorkappavar;
    }                           input;

  double                        dgamma[(5-1)];
};

static void
test_dqfuncdgamma (void)
{
  DQfuncDgammaTestDatum data[] = 
    {{{0.0176261, {0.399847, 0.494823, 0.653572}, {0.0210253, 0.0422669,  0.958331, 0.743931, 0.648998, 0.433836, 0.935396, 0.156531,  0.0455172, 0.72575, 0.84073, 0.936286, 0.492522, 0.710592,  0.770085, 0.187135}, {0.408365, 0.441243, 0.0395614,  0.638024}, {0.390739, 0.0413962, 0.544738, 0.984453, 0.369714,  0.999129, 0.586407, 0.240522, 0.720716, 0.565293, 0.651011,  0.0839912, 0.675199, 0.839544, 0.810281}, {0.147705, 0.182678,  0.128951, 0.040196,  0.96057}, {{0, 1, 0}, {0, 0, 0}, {1, 1, 2}, {1, 0, 0}, {0, 0,  1}, {1, 2, 3}, {2, 2, 4}, {0, 1, 2}}, 0.774312, 0.687708,  0.000634514, 0.322546, 0.383573, 0.646312, 0.455896, 0.338093,  0.0138587, 0.647183, 0.86949, 0.0975711}, {-4.81861, 0.17376,  10.7177, -2.60707}}, {{0.293142, {0.0818897, 0.218479,  0.0135799}, {0.617943, 0.242346, 0.408198, 0.865875, 0.435266,  0.113395, 0.368002, 0.905305, 0.660953, 0.425686, 0.367367,  0.582759, 0.277381, 0.779374, 0.911471, 0.244667}, {0.263522,  0.132192, 0.041981, 0.147095}, {0.97038, 0.050302, 0.823502,  0.133515, 0.352436, 0.807956, 0.415305, 0.267641, 0.917171,  0.694561, 0.047303, 0.362336, 0.256217, 0.268875,  0.679936}, {0.779576, 0.978837, 0.4895, 0.768465,  0.53491}, {{0, 1, 1}, {0, 1, 3}, {0, 2, 2}, {3, 0, 0}, {0, 0,  2}, {0, 1, 2}, {1, 1, 2}, {3, 1, 3}}, 0.715315, 0.357309,  0.726484, 0.387814, 0.744935, 0.307007, 0.902982, 0.254299,  0.392499, 0.499051, 0.487677, 0.986658}, {10.421, 14.5847, 28.0954,  16.7309}}, {{0.475328, {0.80449, 0.440374, 0.624322}, {0.21911,  0.535615, 0.760438, 0.844746, 0.240274, 0.0461149, 0.991973,  0.309836, 0.524959, 0.688806, 0.265489, 0.922022, 0.780024,  0.3818, 0.362507, 0.667723}, {0.387525, 0.882749, 0.87483,  0.681065}, {0.912198, 0.0782591, 0.434456, 0.0567423, 0.693087,  0.542644, 0.674017, 0.211996, 0.452813, 0.496529, 0.682044,  0.90216, 0.927854, 0.807723, 0.416555}, {0.980138, 0.14783,  0.425923, 0.0540483,  0.312416}, {{3, 2, 1}, {0, 2, 4}, {1, 1, 3}, {3, 1, 1}, {3, 1,  2}, {1, 1, 1}, {1, 2, 4}, {2, 0, 1}}, 0.760305, 0.543174,  0.179218, 0.631351, 0.848108, 0.464915, 0.744763, 0.574609,  0.15502, 0.922271, 0.0707454,  0.362612}, {0.203645, -6.52778, -4.18637, -0.550437}}, {{0.702207, {0.425742, 0.388701, 0.460452}, {0.774353, 0.618019, 0.972146,  0.480314, 0.626522, 0.192096, 0.918097, 0.167898, 0.866217,  0.648922, 0.738879, 0.536547, 0.0181099, 0.184007, 0.994116,  0.961938}, {0.863089, 0.261736, 0.923371, 0.599326}, {0.160882,  0.835994, 0.53467, 0.138874, 0.38653, 0.217974, 0.562524, 0.65856,  0.760007, 0.0258779, 0.644426, 0.490662, 0.89379, 0.376956,  0.905547}, {0.954115, 0.87568, 0.192949, 0.911431,  0.992176}, {{3, 0, 3}, {1, 0, 3}, {3, 1, 3}, {2, 1, 1}, {0, 1,  4}, {1, 0, 4}, {1, 2, 0}, {3, 2, 2}}, 0.0125904, 0.931213,  0.98806, 0.39285, 0.851708, 0.0952199, 0.453391, 0.253977,  0.465179, 0.877246, 0.890867, 0.595417}, {-0.536192,  65.7567, -7.36706, -0.463314}}, {{0.705171, {0.851368, 0.24644,  0.104755}, {0.811382, 0.474412, 0.340893, 0.15064, 0.935702,  0.281463, 0.429462, 0.158464, 0.923111, 0.350249, 0.441401,  0.765614, 0.0714033, 0.255029, 0.988011, 0.511637}, {0.606225,  0.377784, 0.0971439, 0.91622}, {0.901053, 0.526416, 0.850704,  0.811466, 0.0896717, 0.0520041, 0.509811, 0.660825, 0.15397,  0.770541, 0.0803493, 0.502361, 0.230859, 0.420292,  0.638948}, {0.736747, 0.159455, 0.165263, 0.650937,  0.22511}, {{3, 0, 4}, {1, 0, 0}, {0, 0, 4}, {3, 2, 1}, {3, 0,  2}, {3, 1, 4}, {1, 1, 4}, {1, 0, 0}}, 0.553231, 0.787479,  0.553794, 0.30889, 0.652177, 0.261063, 0.70309, 0.497424, 0.562506,  0.209059, 0.193279, 0.836599}, {-0.0388205, 3.78422,  5.36965, -11.4449}}, {{0.408536, {0.438518, 0.11293,  0.334238}, {0.177677, 0.0182256, 0.473982, 0.597491, 0.0182219,  0.852963, 0.823044, 0.37238, 0.464991, 0.065484, 0.269251,  0.0634909, 0.812814, 0.804421, 0.566161, 0.566067}, {0.250309,  0.595362, 0.372882, 0.729468}, {0.841773, 0.156844, 0.259952,  0.39523, 0.664096, 0.138619, 0.78597, 0.79774, 0.645874, 0.285656,  0.962926, 0.425359, 0.180882, 0.220172, 0.693675}, {0.361868,  0.368068, 0.415751, 0.127515,  0.795801}, {{1, 0, 4}, {3, 2, 0}, {1, 0, 3}, {3, 1, 0}, {0, 0,  4}, {2, 2, 4}, {3, 2, 4}, {3, 1, 2}}, 0.11776, 0.820389,  0.754633, 0.0663336, 0.275987, 0.663544, 0.494681, 0.671103,  0.611891, 0.524926, 0.70871, 0.873364}, {115.317, -1.67681,  1.2227, -2.38565}}, {{0.966017, {0.23927, 0.745784,  0.448005}, {0.785135, 0.0190987, 0.0521086, 0.0861366, 0.417067,  0.603348, 0.924594, 0.290335, 0.299307, 0.782959, 0.169961,  0.224002, 0.0233202, 0.119415, 0.675281, 0.552898}, {0.411429,  0.594489, 0.96657, 0.679534}, {0.445412, 0.355219, 0.220786,  0.231529, 0.660277, 0.33612, 0.168678, 0.145393, 0.243211,  0.732772, 0.244084, 0.855058, 0.943904, 0.949813,  0.0741225}, {0.631056, 0.920584, 0.830398, 0.398842,  0.078158}, {{2, 1, 3}, {1, 0, 4}, {3, 1, 3}, {2, 0, 1}, {0, 2,  4}, {2, 2, 2}, {0, 0, 4}, {2, 1, 4}}, 0.509154, 0.235909,  0.432272, 0.398624, 0.0637423, 0.88069, 0.211485, 0.167095,  0.403465, 0.54457, 0.0428076,  0.0217018}, {-2.041, -16.0138, -63.7776, -29.0474}}, {{0.160254, {0.811798, 0.798724, 0.166644}, {0.21635, 0.861985, 0.724601,  0.535588, 0.295767, 0.0315876, 0.325759, 0.45743, 0.786613,  0.795679, 0.893488, 0.0588062, 0.72287, 0.914989, 0.682003,  0.891712}, {0.319405, 0.370419, 0.639195, 0.87001}, {0.159151,  0.55862, 0.840471, 0.703366, 0.942801, 0.696635, 0.11587,  0.167778, 0.647034, 0.665047, 0.79011, 0.710347, 0.860421,  0.869369, 0.896623}, {0.651541, 0.137551, 0.95438, 0.21462,  0.75983}, {{0, 2, 4}, {0, 2, 2}, {2, 1, 1}, {3, 2, 1}, {3, 1,  0}, {3, 0, 3}, {1, 0, 0}, {0, 0, 0}}, 0.818146, 0.583961,  0.575425, 0.88982, 0.658995, 0.0253409, 0.734954, 0.186454,  0.716194, 0.328706, 0.619084, 0.0186767}, {2.50504, 452.675,  2.957, -5.92933}}, {{0.0691602, {0.663658, 0.828974,  0.308329}, {0.208739, 0.79429, 0.932351, 0.656788, 0.0711881,  0.83991, 0.717731, 0.896958, 0.253042, 0.255949, 0.142306,  0.00713854, 0.594048, 0.230608, 0.407352, 0.820684}, {0.877854,  0.901902, 0.788268, 0.802008}, {0.808694, 0.238243, 0.959294,  0.493678, 0.599955, 0.443954, 0.0269431, 0.83689, 0.528767,  0.604044, 0.309212, 0.939932, 0.275724, 0.348095,  0.166906}, {0.932793, 0.681676, 0.117488, 0.759554,  0.112109}, {{0, 1, 0}, {0, 1, 2}, {3, 0, 2}, {3, 1, 4}, {1, 1,  1}, {3, 0, 3}, {0, 1, 2}, {2, 1, 0}}, 0.803822, 0.215586,  0.971285, 0.310101, 0.995129, 0.977342, 0.0119911, 0.816423,  0.395174, 0.533389, 0.985048,  0.979533}, {-50.3309, -31.8934, -21.6764, -19.2121}}, {{0.866407, {0.929345, 0.675836, 0.0396012}, {0.590683, 0.58125, 0.50893,  0.106808, 0.909007, 0.463762, 0.749377, 0.994699, 0.105184,  0.248176, 0.778091, 0.684598, 0.110056, 0.270834, 0.7661,  0.868174}, {0.714882, 0.737445, 0.781052, 0.888641}, {0.848475,  0.8081, 0.105216, 0.84904, 0.257792, 0.226851, 0.596286, 0.742232,  0.348785, 0.763089, 0.846909, 0.747533, 0.2436, 0.514913,  0.0688175}, {0.0629357, 0.133545, 0.244079, 0.302717,  0.194761}, {{1, 2, 2}, {3, 2, 3}, {0, 2, 2}, {2, 2, 1}, {1, 2,  3}, {0, 1, 1}, {1, 2, 0}, {2, 1, 1}}, 0.418663, 0.506634,  0.521665, 0.30612, 0.570188, 0.698534, 0.416449, 0.45708, 0.312397,  0.471683, 0.820163,  0.714848}, {-6.52115, -5.7416, -2.99852, -6.09749}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      ParameterizedNormalDistribution priorlogalpha = 
        parameterized_normal_distribution (data[i].input.priorlogalphavar);

      ParameterizedNormalDistribution priortau =
        parameterized_normal_distribution (data[i].input.priortauvar);

      NormalDistribution priorgammanormal[4] = {
          normal_distribution (data[i].input.priorgamma1mean,
                               data[i].input.priorgamma1var),
          normal_distribution (data[i].input.priorgamma2mean,
                               data[i].input.priorgamma2var),
          normal_distribution (data[i].input.priorgamma3mean,
                               data[i].input.priorgamma3var),
          normal_distribution (data[i].input.priorgamma4mean,
                               data[i].input.priorgamma4var)
      };

      Distribution* priorgamma[4] = {
          &priorgammanormal[0].base,
          &priorgammanormal[1].base,
          &priorgammanormal[2].base,
          &priorgammanormal[3].base
      };

      NormalDistribution priorkappa = 
        normal_distribution (data[i].input.priorkappamean,
                             data[i].input.priorkappavar);

      double dkappa;
      double dlogalpha[3];
      double dtau[4*(5-1)];
      double dgamma[(5-1)];

      dqfunc (&dkappa,
              dlogalpha,
              dtau,
              dgamma,
              data[i].input.kappa,
              data[i].input.logalpha,
              4,
              5,
              data[i].input.tau,
              3,
              data[i].input.gamma,
              data[i].input.pz,
              data[i].input.ratings,
              8,
              &priorkappa.base,
              &priorlogalpha.base,
              &priortau.base,
              priorgamma);

      for (unsigned int j = 0; j < (5-1); ++j)
        {
          assert (      fabs (dgamma[j] - data[i].dgamma[j]) 
                     <= 1e-4 * (1 + fabs (dgamma[j]) + fabs (data[i].dgamma[j]))
                  || (fprintf (stderr, "fail: %g != %g\n", dgamma[j], data[i].dgamma[j]),
                      0));
        }
    }
}

int 
main (void)
{
  srand48 (69);

  test_qfunc ();
  test_dqfuncdkappa ();
  test_dqfuncdlogalpha ();
  test_dqfuncdtau ();
  test_dqfuncdgamma ();

  return 0;
}
